﻿//using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Text;

//using System.Threading;
//using System.Net;
//using System.Net.Sockets;

//namespace NetworkingLibrary
//{
//    public class ManagerServer
//    {
//        private static int bufferSize = 100000;

//        /// <summary>
//        /// The size of the buffer to use when sending/receiving data. Default value is 100000.
//        /// </summary>
//        public static int BufferSize
//        {
//            get
//            {
//                return bufferSize;
//            }
//            set
//            {
//                if (value >= (Properties.Settings.Default.MaxBufferSize - GlobalMethods.LengthBytesLength))
//                {
//                    throw new InvalidCastException("Value must be less than " + (Properties.Settings.Default.MaxBufferSize - GlobalMethods.LengthBytesLength).ToString());
//                }
//                else
//                {
//                    bufferSize = value;
//                }
//            }
//        }

//        private bool Initialised = false;
//        private bool terminating = false;

//        /// <summary>
//        /// Whether the server is terminating. Can be set to true but not to false.
//        /// </summary>
//        public bool Terminating
//        {
//            get
//            {
//                return terminating;
//            }
//            set
//            {
//                terminating = terminating ? true : value;
//            }
//        }

//        private TcpListener TheListener;
//        private int maxConnections = 100;

//        /// <summary>
//        /// The maximum number of connections the server should accept. Default value is 100;
//        /// </summary>
//        public int MaxConnections
//        {
//            get
//            {
//                return maxConnections;
//            }
//            set
//            {
//                try
//                {
//                    if (value > -1)
//                    {
//                        maxConnections = value;
//                        while (Clients.IClients.Count > maxConnections)
//                        {
//                            Guid TheAddress = Clients.Last().Key;
//                            ManagerServerClient Client = Clients[TheAddress];
//                            if (TheClients.IClient != null)
//                            {
//                                TheClient.Stop();
//                                Clients.Remove(TheAddress);
//                            }
//                        }
//                    }
//                    else
//                    {
//                        OnError.Invoke(new ErrorMessageEventArgs("Value must be greater than or equal to 0"));
//                    }
//                }
//                catch (Exception e)
//                {
//                    OnError.Invoke(new ErrorMessageEventArgs(e.Message));
//                }
//            }
//        }

//        private AsyncCallback AcceptSocketCallback;

//        private Dictionary<Guid, ManagerServerClients.IClient> Clients.IClients = new Dictionary<Guid, ManagerServerClients.IClient>();

//        /// <summary>
//        /// A dictionary list of all the current connections that the server has accepted.
//        /// </summary>
//        public Dictionary<Guid, ManagerServerClients.IClient> AllClients.IClients
//        {
//            get
//            {
//                return Clients.IClients;
//            }
//        }

//        /// <summary>
//        /// Fired when any error occurs.
//        /// </summary>
//        public event ErrorMessageDelegate OnError;

//        /// <summary>
//        /// Fired when the server accepts the maximum number of connections allowed.
//        /// </summary>
//        public event MaxConnectionsDelegate OnMaxConnections;

//        public delegate void MessageReceivedDelegate(ManagerServerMessageReceivedEventArgs e);
//        /// <summary>
//        /// Fired when the server receives a message (data).
//        /// </summary>
//        public event MessageReceivedDelegate OnMessageReceived;

//        public delegate void Clients.IClientDisconnectDelegate(ManagerServerDisconnectedEventArgs e);
//        /// <summary>
//        /// Fired when a client disconnect from the server.
//        /// </summary>
//        public event Clients.IClientDisconnectDelegate OnClients.IClientDisconnect;

//        private Dictionary<Guid, ManagerServerClients.IClient> Servers = new Dictionary<Guid, ManagerServerClients.IClient>();
//        /// <summary>
//        /// A list of all the servers the manager server knows about.
//        /// </summary>
//        public Dictionary<Guid, ManagerServerClients.IClient> AllServers
//        {
//            get
//            {
//                return Servers;
//            }
//        }

//        /// <summary>
//        /// Fired when a connection is accepted.
//        /// </summary>
//        public event ConnectedDelegate OnConnectionAccepted;


//        /// <summary>
//        /// Default constructor.
//        /// </summary>
//        /// <param name="OnMaxConnectionsReached">See OnMaxConnections event</param>
//        /// <param name="OnAMessageReceived">See OnMessageReceived event</param>
//        public ManagerServer(MaxConnectionsDelegate OnMaxConnectionsReached, MessageReceivedDelegate OnAMessageReceived)
//        {
//            OnError += new ErrorMessageDelegate(ManagerServer_OnError);
//            OnMaxConnections += OnMaxConnectionsReached;
//            OnMessageReceived += OnAMessageReceived;
//        }

//        private void ManagerServer_OnError(ErrorMessageEventArgs e)
//        {
//            //Fillin - in case user does not use this event
//        }

//        private bool Initialise(int Port)
//        {
//            try
//            {
//                TheListener = new TcpListener(Dns.GetHostEntry(Dns.GetHostName()).AddressList.First(), Port);
//                AcceptSocketCallback = new AsyncCallback(AcceptSocket);
//                return true;
//            }
//            catch (Exception e)
//            {
//                OnError.Invoke(new ErrorMessageEventArgs(e.Message));
//            }
//            return false;
//        }
             
//        /// <summary>
//        /// Initialises the server and starts it listening for connections
//        /// </summary>
//        /// <param name="Port">The port number to listen on.</param>
//        /// <param name="MaximumConnections">See MaxConnections property.</param>
//        /// <returns>Returns true if server is initialised and starts listening.</returns>
//        public bool Start(int Port, int MaximumConnections)
//        {
//            try
//            {
//                terminating = false;

//                bool OK = true;

//                if (!Initialised)
//                {
//                    OK = Initialised = Initialise(Port);
//                }

//                if (OK)
//                {
//                    MaxConnections = MaximumConnections;
//                    TheListener.Start(MaxConnections);
//                    TheListener.BeginAcceptSocket(AcceptSocketCallback, null);
//                }

//                return OK;
//            }
//            catch (Exception e)
//            {
//                OnError.Invoke(new ErrorMessageEventArgs(e.Message));
//            }
//            return false;
//        }
//        /// <summary>
//        /// Stops the server listening for connections and ends all existing connections.
//        /// </summary>
//        /// <returns>Returns true if server is stopped and all existing connections are successfully closed.</returns>
//        public bool Stop()
//        {
//            try
//            {
//                Terminating = true;

//                TheListener.Stop();
//                TheListener = null;

//                int Fails = 0;
//                for (int i = 0; i < Clients.IClients.Count; i++)
//                {
//                    ManagerServerClients.IClient AClients.IClient = Clients.IClients.ElementAt(i).Value;
//                    AClients.IClient.Terminating = true;
//                    if (!AClients.IClient.Stop())
//                    {
//                        Fails++;
//                    }
//                }

//                return Fails == 0 ? true : false;
//            }
//            catch (Exception e)
//            {
//                OnError.Invoke(new ErrorMessageEventArgs(e.Message));
//            }
//            return false;
//        }

//        private void AcceptSocket(IAsyncResult Result)
//        {
//            try
//            {
//                if (!Terminating)
//                {
//                    if (Clients.IClients.Count < MaxConnections)
//                    {
//                        if (Result != null && TheListener != null)
//                        {
//                            Socket TheSocket = TheListener.EndAcceptSocket(Result);
//                            if (TheSocket != null)
//                            {
//                                TheSocket.Blocking = false;
//                                TheSocket.DontFragment = false;
//                                TheSocket.LingerState = new LingerOption(true, 5);
//                                TheSocket.NoDelay = true;
//                                TheSocket.ReceiveBufferSize = BufferSize;
//                                TheSocket.SendBufferSize = BufferSize;

//                                if (TheSocket.Connected)
//                                {
//                                    ManagerServerClients.IClient TheClients.IClient = new ManagerServerClients.IClient(TheSocket, ((IPEndPoint)TheSocket.RemoteEndPoint).Address, Guid.NewGuid());
//                                    TheClients.IClient.OnMessageReceived += new MessageReceivedDelegate(TheClients.IClient_OnMessageReceived);
//                                    TheClients.IClient.OnDisconnected += new ManagerServerClients.IClient.DisconnectedDelegate(TheClients.IClient_OnDisconnected);
//                                    Clients.IClients.Add(TheClients.IClient.ID, TheClients.IClient);
//                                    if (!TheClients.IClient.Start())
//                                    {
//                                        TheSocket.Close();
//                                        try
//                                        {
//                                            Clients.IClients.Remove(TheClients.IClient.ID);
//                                        }
//                                        catch
//                                        {
//                                        }
//                                    }
//                                    else
//                                    {
//                                        OnConnectionAccepted.Invoke();
//                                    }
//                                }

//                                TheListener.BeginAcceptSocket(AcceptSocketCallback, null);
//                            }
//                        }
//                    }
//                    else
//                    {
//                        if (OnMaxConnections != null)
//                        {
//                            OnMaxConnections.Invoke();
//                        }
//                    }
//                }
//            }
//            catch (Exception e)
//            {
//                OnError.Invoke(new ErrorMessageEventArgs(e.Message));
//            }
//        }

//        private void TheClients.IClient_OnDisconnected(ManagerServerDisconnectedEventArgs e)
//        {
//            try
//            {
//                Clients.IClients.Remove(e.TheClients.IClient.ID);
//                try
//                {
//                    OnClients.IClientDisconnect.Invoke(e);
//                }
//                catch
//                {
//                }
//            }
//            catch
//            {
//            }
//        }

//        private void TheClients.IClient_OnMessageReceived(ManagerServerMessageReceivedEventArgs e)
//        {
//            try
//            {
//                if (e.TheMessageObject != null)
//                {
//                    if (!e.TheMessageObject.CloseConnection)
//                    {                        
//                        if (e.TheMessageObject.TheMessageType == ManagerServerMessageType.AddServer)
//                        {
//                            if (!Servers.ContainsKey(e.TheClients.IClient.ID))
//                            {
//                                Servers.Add(e.TheClients.IClient.ID, e.TheClients.IClient);
//                            }
//                        }
//                        else if (e.TheMessageObject.TheMessageType == ManagerServerMessageType.RemoveServer)
//                        {
//                            if (Servers.ContainsKey(e.TheClients.IClient.ID))
//                            {
//                                Servers.Remove(e.TheClients.IClient.ID);
//                            }
//                            else
//                            {
//                                try
//                                {
//                                    List<ManagerServerClients.IClient> PotClients.IClients = (from Sers in Servers.Values
//                                                                            where (Sers.RemoteAddress.ToString() == e.TheClients.IClient.RemoteAddress.ToString())
//                                                                            select Sers).ToList();
//                                    if (PotClients.IClients != null && PotClients.IClients.Count > 0)
//                                    {
//                                        foreach (ManagerServerClients.IClient AClients.IClient in PotClients.IClients)
//                                        {
//                                            Servers.Remove(AClients.IClient.ID);
//                                        }
//                                    }
//                                }
//                                catch
//                                {
//                                }
//                            }
//                        }
//                        else if (e.TheMessageObject.TheMessageType == ManagerServerMessageType.GetServers)
//                        {
//                            List<IPAddress> ServerAddresses = new List<IPAddress>();
//                            for (int i = 0; i < Servers.Count; i++)
//                            {
//                                ManagerServerClients.IClient AClients.IClient = Servers.ElementAt(i).Value;
//                                if (!ServerAddresses.Contains(AClients.IClient.RemoteAddress))
//                                {
//                                    try
//                                    {
//                                        ServerAddresses.Add(AClients.IClient.RemoteAddress);
//                                    }
//                                    catch
//                                    {
//                                    }
//                                }
//                                else
//                                {
//                                    Servers.Remove(AClients.IClient.ID);
//                                }
//                            }
//                            ManagerServerMessageObject TheObj = new ManagerServerMessageObject(GlobalMethods.ToBytes(ServerAddresses), ManagerServerMessageType.ServersResponse, false);
//                            e.TheClients.IClient.Send(GlobalMethods.ToBytes(TheObj));
//                        }
//                        else if (e.TheMessageObject.TheMessageType == ManagerServerMessageType.Other)
//                        {
//                        }
//                    }
//                    else
//                    {
//                        e.TheClients.IClient.Stop();
//                    }
//                    OnMessageReceived.Invoke(e);
//                }
//            }
//            catch
//            {
//            }
//        }

//        /// <summary>
//        /// Sends the specified data to all clients.
//        /// </summary>
//        /// <param name="TheBuffer">The data in byte array form. (Use GlobalMethods.ToBytes to convert a serialisable object to a byte array)</param>
//        /// <returns>Returns true if data is sent to all clients.</returns>
//        public bool Send(byte[] TheBuffer)
//        {
//            try
//            {
//                if (Initialised && !Terminating)
//                {
//                    bool All = true;

//                    foreach (ManagerServerClients.IClient AClients.IClient in Clients.IClients.Values)
//                    {
//                        bool Sent = AClients.IClient.Send(TheBuffer);
//                        All = !All ? All : Sent;
//                    }

//                    return All;
//                }
//            }
//            catch (Exception e)
//            {
//                OnError.Invoke(new ErrorMessageEventArgs(e.Message));
//            }
//            return false;
//        }
//        /// <summary>
//        /// Sends the specified data to the specified client.
//        /// </summary>
//        /// <param name="TheBuffer">The data in byte array form. (Use GlobalMethods.ToBytes to convert a serialisable object to a byte array)</param>
//        /// <param name="ToID">The ID of the client to send the data to.</param>
//        /// <returns>Returns true if data is sent or no client is found with the correct ID.</returns>
//        public bool SendTo(byte[] TheBuffer, Guid ToID)
//        {
//            try
//            {
//                if (Initialised && !Terminating)
//                {
//                    bool Sent = true;

//                    foreach (ManagerServerClients.IClient AClients.IClient in Clients.IClients.Values)
//                    {
//                        if (AClients.IClient.ID == ToID)
//                        {
//                            Sent = AClients.IClient.Send(TheBuffer);
//                        }
//                    }

//                    return Sent;
//                }
//            }
//            catch (Exception e)
//            {
//                OnError.Invoke(new ErrorMessageEventArgs(e.Message));
//            }
//            return false;
//        }
//        /// <summary>
//        /// Sends the specified data to all clients except the specified client.
//        /// </summary>
//        /// <param name="TheBuffer">The data in byte array form. (Use GlobalMethods.ToBytes to convert a serialisable object to a byte array)</param>
//        /// <param name="ExcludeID">The ID of the client to exclude.</param>
//        /// <returns>Returns true if data is sent to all clients excluding the specified client.</returns>
//        public bool Send(byte[] TheBuffer, Guid ExcludeID)
//        {
//            try
//            {
//                if (Initialised && !Terminating)
//                {
//                    bool All = true;

//                    foreach (ManagerServerClients.IClient AClients.IClient in Clients.IClients.Values)
//                    {
//                        if (AClients.IClient.ID != ExcludeID)
//                        {
//                            bool Sent = AClients.IClient.Send(TheBuffer);
//                            All = !All ? All : Sent;
//                        }
//                    }

//                    return All;
//                }
//            }
//            catch (Exception e)
//            {
//                OnError.Invoke(new ErrorMessageEventArgs(e.Message));
//            }
//            return false;
//        }
//    }

//    public class ManagerServerMessageReceivedEventArgs : EventArgs
//    {
//        /// <summary>
//        /// The message that was received.
//        /// </summary>
//        public ManagerServerMessageObject TheMessageObject;
//        /// <summary>
//        /// The client the data was received from.
//        /// </summary>
//        public ManagerServerClients.IClient TheClients.IClient;

//        internal ManagerServerMessageReceivedEventArgs(ManagerServerMessageObject AnMO)
//        {
//            TheMessageObject = AnMO;
//        }
//        internal ManagerServerMessageReceivedEventArgs(ManagerServerMessageObject AnMO, ManagerServerClients.IClient AClients.IClient)
//        {
//            TheMessageObject = AnMO;
//            TheClients.IClient = AClients.IClient;
//        }
//    }

//    public class ManagerServerClients.IClient
//    {
//        private Socket TheSocket;
//        private IPAddress remoteAddress;

//        /// <summary>
//        /// The IP address of the connections remote end point.
//        /// </summary>
//        public IPAddress RemoteAddress
//        {
//            get
//            {
//                return remoteAddress;
//            }
//        }
//        /// <summary>
//        /// The client's ID.
//        /// </summary>
//        public Guid ID;

//        /// <summary>
//        /// Whether the client is terminating or not.
//        /// </summary>
//        internal bool Terminating = false;

//        internal delegate void DisconnectedDelegate(ManagerServerDisconnectedEventArgs e);
//        internal event DisconnectedDelegate OnDisconnected;

//        private ManualResetEvent TerminateWait = new ManualResetEvent(false);

//        private AsyncCallback ReceiveCallback;

//        internal event ManagerServer.MessageReceivedDelegate OnMessageReceived;

//        internal ManagerServerClients.IClient(Socket ASocket, IPAddress ARemoteAddress, Guid AnID)
//        {
//            TheSocket = ASocket;
//            remoteAddress = ARemoteAddress;
//            ID = AnID;
//        }

//        internal bool Start()
//        {
//            try
//            {
//                ReceiveCallback = new AsyncCallback(Read);
//                byte[] TheBuffer = new byte[ManagerServer.BufferSize];
//                TheSocket.BeginReceive(TheBuffer, 0, TheBuffer.Length, SocketFlags.None, ReceiveCallback, TheBuffer);
//                return true;
//            }
//            catch
//            {
//            }
//            return false;
//        }
        
//        private void Read(IAsyncResult Result)
//        {
//            try
//            {
//                int BytesRead = TheSocket.EndReceive(Result);

//                if (!Terminating)
//                {
//                    if (TheSocket.Connected)
//                    {
//                        byte[] TheBuffer = new byte[ManagerServer.BufferSize];
//                        TheSocket.BeginReceive(TheBuffer, 0, TheBuffer.Length, SocketFlags.None, ReceiveCallback, TheBuffer);
//                    }
//                    else
//                    {
//                        Stop();
//                    }
//                }

//                if (BytesRead > 0)
//                {
//                    List<byte[]> AllMessages = GlobalMethods.GetAllMessages((byte[])(Result.AsyncState));
//                    for (int i = 0; i < AllMessages.Count; i++)
//                    {
//                        OnMessageReceived.Invoke(new ManagerServerMessageReceivedEventArgs((ManagerServerMessageObject)(GlobalMethods.FromBytes(AllMessages[i])), this));
//                    }
//                }
//                else
//                {
//                    Stop();
//                }
//            }
//            catch
//            {
//                if (!TheSocket.Connected)
//                {
//                    Stop();
//                }
//            }
//        }

//        /// <summary>
//        /// Sends the specified data to the client.
//        /// </summary>
//        /// <param name="TheBuffer">The data in byte array form. (Use GlobalMethods.ToBytes to convert a serialisable object to a byte array)</param>
//        /// <returns>Returns true if data is sent to the client.</returns>
//        public bool Send(byte[] TheBuffer)
//        {
//            try
//            {
//                if (!TheSocket.Connected)
//                {
//                    Stop();
//                }
//                else
//                {
//                    TheSocket.Send(TheBuffer);
//                    return true;
//                }
//            }
//            catch
//            { 
//            }
//            return false;
//        }

//        internal bool Stop()
//        {
//            try
//            {
//                Terminating = true;

//                TheSocket.Close();
//                OnDisconnected.Invoke(new ManagerServerDisconnectedEventArgs(this));

//                return !TheSocket.Connected;
//            }
//            catch
//            {
//            }
//            return false;
//        }
//    }

//    /// <summary>
//    /// Specific types of server message.
//    /// </summary>
//    public enum ManagerServerMessageType
//    {
//        /// <summary>
//        /// Will cause the manager server to automatically add the client that it receives this type of message from to its list of servers.
//        /// </summary>
//        AddServer,
//        /// <summary>
//        /// Will cause the manager server to automatically remove the client that it receives this type of message from to its list of servers.
//        /// </summary>
//        RemoveServer,
//        /// <summary>
//        /// Will cause the manager server to automatically send the client that it receives this type of message from a copy of its list of servers.
//        /// </summary>
//        GetServers,
//        /// <summary>
//        /// The type of message sent back when a GetServers message is sent to the manager server. The data sent back with this type of message is an IP address list.
//        /// </summary>
//        ServersResponse,
//        /// <summary>
//        /// Specifies that the message is used for something other than the default message types.
//        /// </summary>
//        Other
//    }

//    [Serializable]
//    public class ManagerServerMessageObject
//    {
//        /// <summary>
//        /// The type of message that was received/sent. Some are programmed by default.
//        /// </summary>
//        public ManagerServerMessageType TheMessageType;
//        /// <summary>
//        /// The data that was received/sent.
//        /// </summary>
//        public byte[] TheBytes;
//        public bool CloseConnection = false;

//        internal ManagerServerMessageObject(byte[] ABytes, ManagerServerMessageType AMessageType, bool ShouldCloseConnection)
//        {
//            TheBytes = ABytes;
//            TheMessageType = AMessageType;
//            CloseConnection = ShouldCloseConnection;
//        }
//    }
//}
